package com.own.component.elastic.entity;

import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.own.component.common.base.entity.po.BaseBean;
import com.own.component.elastic.model.CustomFieldValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.springframework.lang.NonNull;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;

/**
 * BaseElasticVo
 *
 * @author chenxueli
 * @date 2022-09-03 20:01:34
 */
@Schema(title = "es搜索引擎对象")
@Getter
@Setter
@Accessors(chain = true)
@ToString
@NoArgsConstructor
public class BaseElasticVo<ELASTIC_PO extends BaseElasticPo<? extends BaseBean>> implements Serializable {

    @Schema(title = "主键id")
    private String id;

    @Schema(title = "创建时间")
    private LocalDateTime gmtCreate;

    @Schema(title = "分数信息")
    private Double searchScore;

    @Schema(title = "排序信息")
    @JsonIgnore
    private List<FieldValue> sort;

    @Schema(title = "高亮数据")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Map<String, List<String>> highlight;

    public void of(Hit<ELASTIC_PO> hit) {
        var source = hit.source();
        if (source == null) {
            return;
        }
        this.searchScore = hit.score();
        // 设置高亮信息
        var highlight = hit.highlight();
        if (highlight != null) {
            this.highlight = highlight;
        }
        // 设置排序分数信息
        var sort = hit.sort();
        if (sort != null) {
            this.sort = sort;
        }
        of(source);
    }

    public void of(@NonNull ELASTIC_PO po) {
        this.id = po.getId();
        this.gmtCreate = po.getGmtCreate() != null ? po.getGmtCreate().withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime() : null;
    }

    /**
     * 获取高亮数据
     *
     * @param key key
     * @return 高亮数据
     */
    public String highlightValue(String key) {
        if (this.highlight == null) {
            return null;
        }
        var list = this.highlight.get(key);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.getFirst();
    }

    /**
     * 替换高亮数据
     *
     * @param key         key
     * @param item        item
     * @param setFunction setFunction
     * @param <X>         X
     */
    public <X extends BaseElasticVo<ELASTIC_PO>> void replaceHighlightValue(String key, X item, BiConsumer<X, String> setFunction) {
        var value = highlightValue(key);
        setFunction.accept(item, value);
    }

    /**
     * 获取自定义字段值
     *
     * @return 自定义字段值
     */
    @JsonIgnore
    public List<CustomFieldValue> getCustomFieldValues() {
        return this.sort == null ? Collections.emptyList() : this.sort.stream().map(CustomFieldValue::new).toList();
    }

}
